package pr.lanmu.config.util;

import cn.hutool.core.io.IoUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import pr.lanmu.config.constant.Code;
import pr.lanmu.config.function.MyConsumer;
import pr.lanmu.config.function.MyDeal;
import pr.lanmu.config.function.MyFunction;
import pr.lanmu.config.function.MySupplier;

import java.io.PrintWriter;

/**
 * 响应统一类
 *
 * @param <T>
 */
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Res<T> {
    private Code code;
    private T body;

    public static Res<?> success() {
        return Res.builder()
                .code(Code.SUCCESS)
                .build();
    }

    public static <T> Res<T> success(T body) {
        return Res.<T>builder()
                .code(Code.SUCCESS)
                .body(body)
                .build();
    }

    public static <T> Res<T> success(MySupplier<T> supplier) {
        return Res.<T>builder()
                .code(Code.SUCCESS)
                .body(supplier.get())
                .build();
    }

    public static <E, T> Res<T> success(MyConsumer<E> consumer, E e) {
        consumer.accept(e);
        return Res.<T>builder()
                .code(Code.SUCCESS)
                .build();
    }

    public static <T, E> Res<T> success(MyFunction<E, T> function, E e) {
        return Res.<T>builder()
                .code(Code.SUCCESS)
                .body(function.apply(e))
                .build();
    }

    public static <T> Res<T> success(MyDeal myDeal) {
        myDeal.deal();
        return Res.<T>builder()
                .code(Code.SUCCESS)
                .build();
    }

    public static Res<?> fail() {
        return Res.builder()
                .code(Code.RUN_ERROR_EXCEPTION)
                .build();
    }

    public static <T> Res<T> fail(String message) {
        return Res.<T>builder()
                .code(new Code(500, message))
                .build();
    }

    public static Res<?> fail(Code code) {
        return Res.builder()
                .code(code)
                .build();
    }

    public static <T> Res<T> fail(Code code, T body) {
        return Res.<T>builder()
                .code(code)
                .body(body)
                .build();
    }

    @SneakyThrows
    public static void json(HttpServletResponse response, Res<?> res) {
        response.setStatus(200);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter pw = response.getWriter();
        pw.write(JSONUtil.toJsonStr(res));
        IoUtil.close(pw);
    }

    public Res<T> setBody(MySupplier<T> supplier) {
        this.body = supplier.get();
        return this;
    }
}
